import {
  canUse,
  isNull,
  PagedList,
  PageParams,
  isUndefined,
  numberToString,
  _pick,
} from "mmb";
import * as brand_distributorpb from "../grpc-client/service/brand_distributor_pb";
import {
  getBgsBrandDistributorOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";
import GrpcErrCode from "../grpc-client/grpcErrCode";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";
import {
  BrandDistributor,
  BecomeBrandDistributorParams,
  UpdateBrandDistributorParams,
  CancelBrandDistributorParams,
  BrandDistributorCacheInfo,
  BrandDistributorWithBrand,
  BrandDistributorWithUser,
} from "./declareTypes";
import { getCache, setCache, makeEntityKey } from "../proxy/redisProxy";

// 考虑用缓存
export const checkBrandDistributor = async (
  userId: string,
  brandDistributorId: string
) => {
  const k = makeBrandDistributorCacheKey(brandDistributorId);
  let cacheItem = await getBrandDistributorInfo(brandDistributorId);
  if (isUndefined(cacheItem)) {
    console.log(`not found distributor:${brandDistributorId},${userId}`);
    return false;
  }
  if (cacheItem.userId !== userId) {
    console.log(`mismatch distributor:${brandDistributorId},${userId}`);
    return false;
  }

  return true;
};

export const getBrandDistributorInfo = async (brandDistributorId: string) => {
  const k = makeBrandDistributorCacheKey(brandDistributorId);
  const cv = await getCache(k);
  let cacheItem: BrandDistributorCacheInfo | undefined = undefined;
  if (canUse(cv)) {
    console.log("checkBrandDistributor use cached value");
    cacheItem = JSON.parse(cv!) as BrandDistributorCacheInfo;
  } else {
    console.log("checkBrandDistributor use query");
    const brandDistributor = await getBrandDistributor(brandDistributorId);
    if (!isUndefined(brandDistributor)) {
      cacheItem = _pick(
        brandDistributor,
        "userId",
        "brandId"
      ) as BrandDistributorCacheInfo;
      await setCache(k, cacheItem); // replay=>OK
    }
  }
  return cacheItem;
};

export const getBrandDistributorInfoSafely = async (
  brandDistributorId: string
) => {
  const brandDistributorInfo = await getBrandDistributorInfo(
    brandDistributorId
  );
  return brandDistributorInfo!;
};

/****************************************************************************************/
/*                                   brand_distributor entity                                 */
/****************************************************************************************/

const makeBrandDistributorCacheKey = makeEntityKey("brand_distributor");

const brandDistributorPbToObject = (
  pb: brand_distributorpb.BrandDistributorEntity
): BrandDistributor => {
  return {
    brandDistributorId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    distributeActivityCount: pb.getDistributeActivityCount(),
    saleAmount: pb.getSaleAmount(),
  };
};

/****************************************************************************************/
/*                                   brand_distributor cmd                                */
/****************************************************************************************/

export const updateBrandDistributor = async ({
  brandDistributorId,
  aliasName,
  remark,
}: UpdateBrandDistributorParams): Promise<BrandDistributor> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req = new brand_distributorpb.UpdateBrandDistributorRequest();

  req.setId(Number(brandDistributorId));
  if (!isUndefined(aliasName)) {
    req.setAliasName(aliasName);
  }
  if (!isUndefined(remark)) {
    req.setRemark(remark);
  }

  return new Promise((resolve, reject) => {
    cl.updateBrandDistributor(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(brandDistributorPbToObject(res.getBrandDistributor()!));
      }
    );
  });
};

export const cancelBrandDistributor = async ({
  brandDistributorId,
}: CancelBrandDistributorParams): Promise<BrandDistributor> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req = new brand_distributorpb.CancelBrandDistributorRequest();

  req.setId(Number(brandDistributorId));

  return new Promise((resolve, reject) => {
    cl.cancelBrandDistributor(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        resolve(brandDistributorPbToObject(res.getBrandDistributor()!));
      }
    );
  });
};

/****************************************************************************************/
/*                                   brand_distributor query                              */
/****************************************************************************************/

export const getBrandDistributor = async (
  brandWarehouseId: string
): Promise<BrandDistributor | undefined> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req = new brand_distributorpb.GetBrandDistributorRequest();

  req.setId(Number(brandWarehouseId));

  return new Promise((resolve, reject) => {
    cl.getBrandDistributor(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          if (opRet.getCode() === GrpcErrCode.NOT_FOUND) {
            resolve(undefined);
            return;
          } else {
            reject(wrapperGrpcError(opRet.getMsg()));
            return;
          }
        }
        resolve(brandDistributorPbToObject(res.getBrandDistributor()!));
      }
    );
  });
};

export const listNormalBrandDistributorsByBrandID = async (
  brandId: string,
  pager: PageParams
): Promise<PagedList<BrandDistributor>> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req =
    new brand_distributorpb.ListNormalBrandDistributorsByBrandIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setBrandId(Number(brandId));

  return new Promise((resolve, reject) => {
    cl.listNormalBrandDistributorsByBrandID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandDistributor> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandDistributorsList()
          .map((u) => brandDistributorPbToObject(u));
        resolve(ret);
      }
    );
  });
};

/****************************************************************************************/
/*                                   brand_distributor joins entity                       */
/****************************************************************************************/

const brandDistributorWithUserPbToObject = (
  pb: brand_distributorpb.BrandDistributorWithUserEntity
): BrandDistributorWithUser => {
  return {
    // brand_distributor
    brandDistributorId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    distributeActivityCount: pb.getDistributeActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // distributor User_Info
    distributorUserNickName: pb.getDistributorUserNickName(),
    distributorUserPic: pb.getDistributorUserPic(),
    // user_stat
    fansCount: pb.getFansCount(),
  };
};

const brandDistributorWithBrandPbToObject = (
  pb: brand_distributorpb.BrandDistributorWithBrandEntity
): BrandDistributorWithBrand => {
  return {
    // brand_distributor
    brandDistributorId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    brandId: `${pb.getBrandId()}`,
    aliasName: pb.getAliasName(),
    became: pbTimestampToJs(pb.getBecame())!,
    remark: pb.getRemark(),
    distributeActivityCount: pb.getDistributeActivityCount(),
    saleAmount: pb.getSaleAmount(),

    // brand
    brandName: pb.getBrandName(),
    brandPic: pb.getBrandPic(),
  };
};


/****************************************************************************************/
/*                                   brand_distributor joins query                        */
/****************************************************************************************/

export interface ListNormalBrandDistributorWithUsersByBrandIDParam {
  brandId: string;
  keyword?: string;
}

export const listNormalBrandDistributorWithUsersByBrandID = async (
  { brandId, keyword }: ListNormalBrandDistributorWithUsersByBrandIDParam,
  pager: PageParams
): Promise<PagedList<BrandDistributorWithUser>> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req =
    new brand_distributorpb.ListNormalBrandDistributorWithUsersByBrandIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setTs(jsTimestampToPb(pager.ts));
  req.setBrandId(Number(brandId));
  if (!isUndefined(keyword)) {
    req.setKeyword(keyword);
  }

  return new Promise((resolve, reject) => {
    cl.listNormalBrandDistributorWithUsersByBrandID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandDistributorWithUser> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandDistributorWithUsersList()
          .map((it) => brandDistributorWithUserPbToObject(it));
        resolve(ret);
      }
    );
  });
};

export const listNormalBrandDistributorWithBrandsByUserID = async (
  userId: string,
  pager: PageParams
): Promise<PagedList<BrandDistributorWithBrand>> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req =
    new brand_distributorpb.ListNormalBrandDistributorWithBrandsByUserIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setUserId(Number(userId));

  return new Promise((resolve, reject) => {
    cl.listNormalBrandDistributorWithBrandsByUserID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandDistributorWithBrand> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandDistributorWithBrandsList()
          .map((it) => brandDistributorWithBrandPbToObject(it));
        resolve(ret);
      }
    );
  });
};


export const listNormalBrandDistributorWithBrandsOfStoreNotOpenByUserID = async (
  userId: string,
  pager: PageParams
): Promise<PagedList<BrandDistributorWithBrand>> => {
  const cl = getBgsBrandDistributorOpSafely();
  const req =
    new brand_distributorpb.ListNormalBrandDistributorWithBrandsOfStoreNotOpenByUserIDRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setUserId(Number(userId));

  return new Promise((resolve, reject) => {
    cl.listNormalBrandDistributorWithBrandsOfStoreNotOpenByUserID(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<BrandDistributorWithBrand> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getBrandDistributorWithBrandsList()
          .map((it) => brandDistributorWithBrandPbToObject(it));
        resolve(ret);
      }
    );
  });
};
